package com.sdx.common.utils;

import com.alibaba.fastjson.JSON;
import com.sdx.exception.SdxError;
import com.sdx.exception.SdxException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;

/**
 * http工具类
 *
 * @author tanbaocai
 * @create 2018-05-20 21:18
 **/
public class HttpUtils {
	private static final Logger log = LoggerFactory.getLogger("HttpUtils");
	private static final String CHARSET_UTF8 = "UTF-8";


	/**
	 * 判断http请求是否返回200码
	 * @param statusLine
	 * @return
	 */
	private static boolean isRequestSuccess(StatusLine statusLine) {
		return statusLine.getStatusCode()==200;
	}


	/**
	 * 发出post请求，返回请求结果
	 * @param postUrl
	 * @param map post参数
	 * @return 返回请求返回内容
	 * @throws IOException
	 * @throws SdxException ，结果码不是200
	 */
	public static String postRequest(String postUrl,Map<String,String> map) throws IOException, SdxException {
		try(
				CloseableHttpClient httpClient = HttpClients.createDefault();
		) {
			HttpPost httpPost = new HttpPost(postUrl);
			List<NameValuePair> nvps = new ArrayList<>();
			for (Map.Entry<String,String> entry :map.entrySet()
					) {
				nvps.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
			}
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
			return postRequest(httpClient,httpPost);
		}

	}

	/**
	 * http下载txt文件
	 *
	 * @return
	 */
	public static ResponseEntity<String> exportTxt(String txtContent,String fileName) {
		if (StringUtils.isEmpty(txtContent)) {
			return null;
		}
		ResponseEntity.BodyBuilder bb = ResponseEntity.ok();
		bb.header("Cache-Control", "no-cache, no-store, must-revalidate");
		bb.header("Content-Disposition", "attachment; filename=" + fileName);
		bb.header("Pragma", "no-cache");
		bb.header("Expires", "0");
		bb.header("Last-Modified", new Date().toString());
		bb.header("ETag", String.valueOf(System.currentTimeMillis()));
		bb.contentLength(txtContent.length());
		bb.contentType(MediaType.parseMediaType("text/plain"));
		return  bb.body(txtContent);
	}
	/**
	 * http写入回应
	 * @param response
	 * @param content
	 */
	public static void writeH5String(HttpServletResponse response, String content) throws IOException {
		response.setHeader("progma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.addHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Content-Type", "text/html;charset=UTF-8");
		response.setCharacterEncoding("UTF-8");
		response.setStatus(200);
		response.setContentLength(content.getBytes("utf-8").length);
		response.setBufferSize(1024);
		try(
				PrintWriter pw = response.getWriter()
        ) {
			pw.write(content);
			pw.flush();
		}
	}

	private static String postRequest(CloseableHttpClient httpClient,HttpPost httpPost) throws IOException, SdxException {
		log.info("request="+EntityUtils.toString(httpPost.getEntity()));
		try(
			CloseableHttpResponse response = httpClient.execute(httpPost)
		) {
			StatusLine statusLine = response.getStatusLine();
			if (isRequestSuccess(statusLine)) {
				HttpEntity responseEntity = response.getEntity();
				String result = EntityUtils.toString(responseEntity,CHARSET_UTF8);
				log.info("response="+result);
				return result;
			} else {
				log.error("post "+httpPost.getURI()+" "+ JSON.toJSONString(httpPost.getEntity())+" statuscode="+statusLine.getStatusCode());
				throw new SdxException(SdxError.HTTP_ERROR,"httppost error,statuscode="+statusLine.getStatusCode());
			}
		}
	}
	/**
	 * https的post请求
	 * @param url
	 * @param content 发送内容
	 * @param key 证书key
	 * @param certFilePath 证书文件路径
	 * @return 返回请求返回内容
	 */
	public static String httpsPost(String url, String content,String key,String certFilePath) throws KeyStoreException, IOException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, CertificateException, SdxException {
		String result = null;
		KeyStore keyStore  = KeyStore.getInstance("PKCS12");
		try(
			FileInputStream instream = new FileInputStream(new File(certFilePath))
		) {
			keyStore.load(instream, key.toCharArray());
		}
		SSLContext sslcontext = SSLContexts.custom()
				.loadKeyMaterial(keyStore, key.toCharArray())
				.build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
				sslcontext,
				new String[] { "TLSv1" },
				null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		try(
			CloseableHttpClient httpclient = HttpClients.custom()
				.setSSLSocketFactory(sslsf)
				.build();
		) {
			HttpPost httpPost = new HttpPost(url);
			StringEntity entity = new StringEntity(content,"UTF-8");
			httpPost.setEntity(entity);
			result = postRequest(httpclient,httpPost);
		}


		return result;
	}

	/**
	 * post请求
	 * @param url 请求url
	 * @param content post内容体
	 * @return 返回响应字符串
	 * @throws IOException
	 */
	public static String httpPost(String url, String content) throws IOException {

		log.info(url);
		log.info("post "+content);
		URL url_news = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) url_news.openConnection();
		conn.setRequestMethod("POST");
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.connect();
		StringBuffer strBuff = new StringBuffer();
		try (
				OutputStream os = conn.getOutputStream()
        ) {
			os.write(content.getBytes("utf-8"));
			os.flush();
		}
		try (
				BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"))
        ) {
			String line = in.readLine();
			while(line!=null) {
				strBuff.append(line);
				line = in.readLine();
			}
		}
		log.info("response "+strBuff.toString());
		return strBuff.toString();
	}

	/**
	 * post请求
	 * @param url 请求url
	 * @return 返回响应字符串
	 * @throws IOException
	 */
	public static String httpGet(String url) throws IOException {

		log.info(url);

		URL url_news = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) url_news.openConnection();
		conn.setRequestMethod("GET");
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.connect();
		StringBuffer strBuff = new StringBuffer();
		try (
				BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"))
        ) {
			String line = in.readLine();
			while(line!=null) {
				strBuff.append(line);
				line = in.readLine();
			}
		}
		log.info("response "+strBuff.toString());
		return strBuff.toString();
	}


	/**
	 * post请求，发送xml格式请求体，返回的也是xml
	 * @param url 请求url
	 * @param xmlBean 需要转换成xml的javabean
	 * @return document
	 */
	public static Document httpPostXML(String url,Object xmlBean) throws IOException, DocumentException {
		//形成xml格式请求字符串
		String xmlContent = null;
		XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
		xStreamForRequestPostData.alias("xml", xmlBean.getClass());
		//将要提交给API的数据对象转换成XML
		xmlContent = xStreamForRequestPostData.toXML(xmlBean);
		String response = httpPost(url,xmlContent);
		Document result = DocumentHelper.parseText(response);
		return result;
	}

	/**
	 * 获取客户端的真实ip地址
	 * @param request
	 * @return
	 */
	public static String getRemoteIP(HttpServletRequest request) {
		String Xip = request.getHeader("X-Real-IP");
		String XFor = request.getHeader("X-Forwarded-For");
		if(!StringUtils.isEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
			//多次反向代理后会有多个ip值，第一个ip才是真实ip
			int index = XFor.indexOf(",");
			if(index != -1){
				return XFor.substring(0,index);
			}else{
				return XFor;
			}
		}
		XFor = Xip;
		if(!StringUtils.isEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
			return XFor;
		}
		if (StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("HTTP_CLIENT_IP");
		}
		if (StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (StringUtils.isEmpty(XFor) || "unknown".equalsIgnoreCase(XFor)) {
			XFor = request.getRemoteAddr();
		}
		return XFor;
	}
	public static void main(String[] args) throws IOException, SdxException {

		String url = "http://m.51sdx.com/sdx-inter/esign/notificationSign";
		Map<String,String> params = new HashMap<>();
		params.put("parentPhone","13510085210");
		params.put("parentName","汪佳佳");
		params.put("invoiceNo","201808092124");

		HttpUtils.httpGet("http://m.51sdx.com/sdx-inter/esign/notificationSign?parentPhone=13510085210&parentName=汪佳佳&invoiceNo=201808092124");
		System.out.println(HttpUtils.postRequest(url,params));
	}
}
